package com.hb.trade.api.expert.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.hb.core.pojo.Attachment;
import com.hb.core.pojo.center.au.dto.OrgDTO;
import com.hb.core.pojo.center.au.dto.UserDTO;
import com.hb.core.pojo.expert.dto.*;
import com.hb.core.pojo.expert.entity.ExpertGroupMembers;
import com.hb.core.pojo.expert.entity.ExpertUser;
import com.hb.trade.api.expert.service.RsaAlgorithmService;
import com.hb.trade.api.expert.util.ExportExtractExpertUtil;
import com.hb.trade.client.center.OrgClient;
import com.hb.trade.client.expert.ExpertClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.util.CollectionUtils;
import org.fzzn.core.auth.shiro.JwtToken;
import org.fzzn.core.auth.shiro.util.CredentialUtil;
import org.fzzn.core.auth.shiro.util.ShiroUtil;
import org.fzzn.core.cache.inmemory.InMemoryService;
import org.fzzn.core.component.jwt.util.JwtUtils;
import org.fzzn.core.file.service.DownloadService;
import org.fzzn.core.model.enums.MsgEnum;
import org.fzzn.core.model.msg.Message;
import org.fzzn.core.model.msg.ResponseDto;
import org.fzzn.core.model.user.login.LoginModel;
import org.fzzn.core.model.user.login.SimpleUserExample;
import org.fzzn.core.util.MsgUtil;
import org.fzzn.core.util.ResultUtil;
import org.fzzn.core.web.anno.Version;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 专家资料库API控制器
 *
 * @author ljs
 * @date 2022-2-10 16:32:04
 */
@Slf4j
@Version(1.0)
@Api(tags = {"专家资料库"})
@RequestMapping("/{version}")
@RestController
public class ApiExpertController {
    protected final ExpertClient expertClient;
    protected final OrgClient orgClient;
    private final RsaAlgorithmService rsaAlgorithmService;

    public ApiExpertController(ExpertClient expertClient,
                               RsaAlgorithmService rsaAlgorithmService,
                               OrgClient orgClient) {
        this.expertClient = expertClient;
        this.rsaAlgorithmService = rsaAlgorithmService;
        this.orgClient = orgClient;
    }

    @ApiOperation(value = "抽取专家", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "majorAmountList", value = "专业以及数量", dataTypeClass = MajorAmount.class)
    })
    @PostMapping("/api/expert/expertExtract")
    public ResponseDto expertExtract(@RequestBody ExpertExtractParam expertExtractParam) {
        expertExtractParam.setOrgId(ShiroUtil.getOrgId());
        return ResultUtil.msg(expertClient.expertExtract(expertExtractParam));
    }

    @ApiOperation(value = "根据父类code获取专业列表", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "parentCode", value = "父类Code", dataTypeClass = String.class)
    })
    @PostMapping("/api/expert/majorList")
    public ResponseDto majorList(@RequestBody ExpertMajorDTO expertMajorDTO) {
        Message result = MsgUtil.success(expertClient.majorList(expertMajorDTO));
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "获取全部专业列表", httpMethod = "POST")
    @ApiImplicitParams({
    })
    @PostMapping("/api/expert/allMajorList")
    public ResponseDto allMajorList(@RequestBody ExpertMajorDTO expertMajorDTO) {
        Message result = MsgUtil.success(expertClient.allMajorList(expertMajorDTO));
        return ResultUtil.msg(result);
    }


    @ApiOperation(value = "分页搜索专家", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "searchParam", value = "搜索参数", dataTypeClass = String.class),
            @ApiImplicitParam(name = "majorName", value = "专业名称", dataTypeClass = String.class)
    })
    @PostMapping("/api/expert/searchExpert")
    public ResponseDto expertSearch(@RequestBody ExpertDTO expertDTO) {
        expertDTO.setOrgId(ShiroUtil.getOrgId());
        Message result = MsgUtil.success(expertClient.expertSearch(expertDTO));
        return ResultUtil.msg(result);
    }
    @ApiOperation(value = "搜索全部专家", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "searchParam", value = "搜索参数", dataTypeClass = String.class),
            @ApiImplicitParam(name = "majorName", value = "专业名称", dataTypeClass = String.class)
    })
    @PostMapping("/api/expert/expertAll")
    public ResponseDto expertAll(@RequestBody ExpertDTO expertDTO) {
        expertDTO.setOrgId(ShiroUtil.getOrgId());
        Message result = expertClient.expertAll(expertDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "添加专家", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "expertName", value = "专家姓名", dataTypeClass = String.class),
            @ApiImplicitParam(name = "idCard", value = "专家身份证号", dataTypeClass = String.class),
            @ApiImplicitParam(name = "sex", value = "性别（0，男；1，女）", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "phoneNumber", value = "手机", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "majorCode", value = "专业编号", dataTypeClass = String.class),
            @ApiImplicitParam(name = "onworkFlag", value = "是否在职（1：在职，0：不在职）", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "company", value = "工作单位", dataTypeClass = String.class)
    })
    @PostMapping("/api/expert/expertSave")
    public ResponseDto expertSave(@RequestBody ExpertDTO expertDTO) {
        expertDTO.setOrgId(ShiroUtil.getOrgId());
        Message result = expertClient.expertSave(expertDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "更新专家信息", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "专家ID", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "expertName", value = "专家姓名", dataTypeClass = String.class),
            @ApiImplicitParam(name = "idCard", value = "专家身份证号", dataTypeClass = String.class),
            @ApiImplicitParam(name = "sex", value = "性别（0，男；1，女）", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "phoneNumber", value = "手机", dataTypeClass = Long.class),
            @ApiImplicitParam(name = "majorCode", value = "专业编号", dataTypeClass = String.class),
            @ApiImplicitParam(name = "onworkFlag", value = "是否在职（1：在职，0：不在职）", dataTypeClass = Integer.class),
            @ApiImplicitParam(name = "company", value = "工作单位", dataTypeClass = String.class)
    })
    @PostMapping("/api/expert/expertUpdate")
    public ResponseDto expertUpdate(@RequestBody ExpertDTO expertDTO) {
        expertDTO.setOrgId(ShiroUtil.getOrgId());
        Message result = expertClient.expertUpdate(expertDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "删除专家信息", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "专家ID", dataTypeClass = Long.class)
    })
    @PostMapping("/api/expert/expertDelete")
    public ResponseDto expertDelete(@RequestBody ExpertDTO expertDTO) {
        Message result = expertClient.expertDelete(expertDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "保存专家组信息", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "expertList", value = "专家信息列表", dataTypeClass = ExpertGroupMembers.class),
            @ApiImplicitParam(name = "projectName", value = "项目名称", dataTypeClass = String.class)
    })
    @PostMapping("/api/expert/expertGroupSave")
    public ResponseDto expertGroupSave(@RequestBody ExpertGroupDTO expertGroupDTO) {
        expertGroupDTO.setOrgId(ShiroUtil.getOrgId());
        Message result = expertClient.expertGroupSave(expertGroupDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "查询当前用户下专家组", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户ID", dataTypeClass = ExpertGroupMembers.class)
    })
    @PostMapping("/api/expert/expertGroupList")
    public ResponseDto expertGroupList(@RequestBody ExpertGroupDTO expertGroupDTO){
        Message result = expertClient.expertGroupList(expertGroupDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "导出专家组详情", notes = "生成专家对应的excel", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "专家组ID", dataTypeClass = ExpertGroupMembers.class)
    })
    @PostMapping("/api/expert/expertGroupDetail")
    public ResponseDto expertGroupDetail(@RequestBody ExpertGroupDTO expertGroupDTO){
        Message<ExpertGroupDTO> result = expertClient.expertGroupDetail(expertGroupDTO);
        if(result.isSuccess() && null != result.getData()){
            ExpertGroupDTO expertMajorDTO = result.getData();
            // 查询公司名称
            Message<OrgDTO> orgInfo = orgClient.getOrgById(expertMajorDTO.getOrgId());
            if(orgInfo.isSuccess() && null != orgInfo.getData()){
                expertMajorDTO.setOrgName(orgInfo.getData().getOrgName());
            }
            try {
                Attachment attachment = ExportExtractExpertUtil.expertExcel(expertMajorDTO);
                return ResultUtil.msg(MsgUtil.success(attachment));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return ResultUtil.msg(MsgUtil.fail("导出抽取记录失败"));
    }

    /**
     * 下载内存中保存的文件
     *
     * @param fileId 该参数为后端生成的字符串保存在redis里面的
     * @return
     * @update ljs
     */
    @ApiOperation(value = "下载内存中保存的文件", notes = "下载内存中保存的文件")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "fileId", value = "招标文件临时ID, 后端提供", dataTypeClass = String.class)
    })
    @GetMapping("/api/expert/download")
    public void downloadFileByMemory(String fileId, HttpServletResponse response) {
        InMemoryService memoryService = SpringUtil.getBean(InMemoryService.class);
        DownloadService downloadService = SpringUtil.getBean(DownloadService.class);
        if (fileId == null) {
            log.warn(MsgEnum.INCORRECT_PARAM.msg());
            return;
        }
        String filePath = memoryService.get(fileId);
        if (StrUtil.isEmpty(filePath)) {
            log.warn("文件不存在或者已经过期");
            return;
        }

        File file = new File(filePath);
        if (file.exists()) {
            downloadService.download(file.getName(), file, response);
        }

        // 删除文件(先不删除)
        // FileUtil.del(file);
    }

    @ApiOperation(value = "删除专家组", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "用户ID", dataTypeClass = ExpertGroupMembers.class)
    })
    @PostMapping("/api/expert/expertGroupDelete")
    public ResponseDto expertGroupDelete(@RequestBody ExpertGroupDTO expertGroupDTO){
        Message result = expertClient.expertGroupDelete(expertGroupDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "专家列表导入专家", notes = "专家列表导入专家", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "文件对象", dataTypeClass = MultipartFile.class),
    })
    @PostMapping("/api/expert/importExcel")
    public ResponseDto importExcel(@RequestParam("file") MultipartFile file) throws IOException {
        ExcelReader reader = ExcelUtil.getReader(file.getInputStream(), 0);
        reader.addHeaderAlias("专家姓名（必填）", "expertName");
        reader.addHeaderAlias("身份证号", "idCard");
        reader.addHeaderAlias("性别（必填）", "sexStr");
        reader.addHeaderAlias("联系方式（必填）", "phoneNumber");
        reader.addHeaderAlias("专业类别（必填）", "majorName");
        reader.addHeaderAlias("工作单位（必填）", "company");

        List<ExpertDTO> read = reader.readAll(ExpertDTO.class);
        if (CollUtil.isEmpty(read)) {
            return ResultUtil.msg(true, read);
        }
        //过滤空值
        read = read.stream().filter(expert -> StrUtil.isNotEmpty(expert.getExpertName())).collect(Collectors.toList());

        int size = read.size();
        for (int i = 0; i < size; i++) {
            String msg = "第" + (i + 2) + "行";
            ExpertDTO expertDTO = read.get(i);
            expertDTO.setOrgId(ShiroUtil.getOrgId());
            if (StrUtil.isEmpty(expertDTO.getExpertName())) {
                return ResultUtil.fail(msg + "专家姓名必填");
            }

            if (expertDTO.getPhoneNumber() == null) {
                return ResultUtil.fail(msg + "联系方式必填");
            }

            if(expertDTO.getPhoneNumber().length() != 11){
                return ResultUtil.fail(msg + "联系方式["+expertDTO.getPhoneNumber()+"]不规范，必须为手机号");
            }
            if (expertDTO.getMajorName() == null) {
                return ResultUtil.fail(msg + "专业类别必填");
            }
        }
        Message result = expertClient.expertImport(read);
        if (result.isFail()){
            return ResultUtil.fail(result.getMessage());
        }

        return ResultUtil.msg(true, read);
    }


    @ApiOperation(value = "抽取专家短信模板列表", httpMethod = "POST")
    @PostMapping("/api/expert/smstpls")
    public ResponseDto smstpls(){
        JSONObject obj = JSONUtil.createObj();
        obj.putOpt("SMS_234397194", "专家您好，您被抽取到于${time}在${address}评标，回复1确认，回复0拒绝。");
        return ResultUtil.msg(true, CollUtil.list(false, obj));
    }

    @ApiOperation(value = "登录专家抽取系统", notes = "登录专家抽取系统", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "用户名", dataTypeClass = String.class, required = true),
            @ApiImplicitParam(name = "password", value = "密码", dataTypeClass = String.class, required = true),
    })
    @PostMapping("/api/expert/expertLogin")
    public ResponseDto expertLogin(@RequestBody ExpertUser userDTO) {
        // 参数验证
        String uname = userDTO.getUsername();
        if (StrUtil.isEmpty(uname)) {
            return ResultUtil.fail(MsgEnum.USERNAME_NOT_ALLOW_EMPTY);
        }
        String pword = userDTO.getPassword();
        if (StrUtil.isEmpty(pword)) {
            return ResultUtil.fail(MsgEnum.PASSWORD_NOT_ALLOW_EMPTY);
        }
        // 利用RSA解密密码
//        String decryptPassword = rsaAlgorithmService.decryptData(userDTO.getPassword());
//        userDTO.setPassword(decryptPassword);

        // 密码设置成密文(MD5)
        userDTO.setPassword(CredentialUtil.md5(pword, UserDTO.INIT_SALT_VALUE));

        Message<ExpertUser> message = expertClient.getExpertUser(userDTO);

        if (message.isFail()) {
            return ResultUtil.msg(MsgEnum.WRONG_USERNAME_PASSWORD);
        }

        ExpertUser expertUser = message.getData();

        // 生成token
        SimpleUserExample tradeUser = new SimpleUserExample();

        // SimpleUserExample必须有id字段，否则下面生成token报错
        tradeUser.setId(expertUser.getId());
        tradeUser.setOrgId(expertUser.getOrgId());
        tradeUser.setUsername(userDTO.getUsername());
        tradeUser.setFullName(expertUser.getFullName());
        tradeUser.setPassword(userDTO.getPassword());

        JSONObject extData = JSONUtil.createObj();
        tradeUser.setExtInfo(extData);

        JwtToken token = new JwtToken(tradeUser);
        ShiroUtil.geneJsonWebToken(token);

        // 将token保存至服务器redis
        LoginModel<SimpleUserExample> model = LoginModel.get(tradeUser, token.getToken());
        JwtUtils.stayToken(model);
        return loginResponse(tradeUser, token.getToken());
    }

    @ApiOperation(value = "专家抽取系统--新增一个用户", notes = "专家抽取系统--新增一个用户", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "用户名", dataTypeClass = String.class, required = true),
            @ApiImplicitParam(name = "password", value = "密码", dataTypeClass = String.class, required = true),
            @ApiImplicitParam(name = "orgId", value = "企业ID", dataTypeClass = Long.class, required = true)
    })
    @PostMapping("/api/expert/expertUserAdd")
    public ResponseDto expertUserAdd(@RequestBody ExpertUser userDTO){
        if (userDTO == null || userDTO.getUsername() == null || userDTO.getPassword() == null){
            return ResultUtil.msg(MsgUtil.fail(MsgEnum.INCORRECT_PARAM.msg()));
        }
        Message<Boolean> result = expertClient.expertUserSave(userDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "专家抽取系统--删除一个用户", notes = "专家抽取系统--删除一个用户", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "删除用户的id", dataTypeClass = Long.class, required = true)
    })
    @PostMapping("/api/expert/expertUserDelete")
    public  ResponseDto expertUserDelete(@RequestBody ExpertUser userDTO){
        if (userDTO == null || userDTO.getId() == null){
            return ResultUtil.msg(MsgUtil.fail(MsgEnum.INCORRECT_PARAM.msg()));
        }
        Message<Boolean> result = expertClient.expertUserDelete(userDTO);
        return ResultUtil.msg(result);
    }

    @ApiOperation(value = "专家抽取系统--修改登录用户信息", notes = "专家抽取系统--修改登录用户信息", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "删除用户的id", dataTypeClass = Long.class, required = true),
            @ApiImplicitParam(name = "username", value = "用户名", dataTypeClass = String.class),
            @ApiImplicitParam(name = "password", value = "密码", dataTypeClass = String.class),
            @ApiImplicitParam(name = "orgId", value = "企业ID", dataTypeClass = Long.class)
    })
    @PostMapping("/api/expert/expertUserUpdate")
    public ResponseDto<?> expertUserUpdate(@RequestBody ExpertUser expertUser){
        String password = expertUser.getPassword();
        if (StrUtil.isNotEmpty(password)){
            expertUser.setPlaintextPassword(password);
            String md5Password = CredentialUtil.md5(password, UserDTO.INIT_SALT_VALUE);
            expertUser.setPassword(md5Password);
        }
        Message<Boolean> result = expertClient.expertUserUpdate(expertUser);
        return ResultUtil.msg(result);
    }

    /**
     * 退出登录
     *
     * @return
     */
    @ApiOperation(value = "退出登录", notes = "退出登录", httpMethod = "POST")
    @PostMapping("/api/expert/logout")
    public ResponseDto logout() {
        boolean logout = ShiroUtil.logout();
        if (logout) {
            return ResultUtil.msg(true);
        }
        log.warn("退出登录失败");
        return ResultUtil.msg(MsgEnum.FAILURE);
    }
    /**
     * 登录信息响应对象
     *
     * @param userEntity
     * @param webToken
     * @return
     */
    private ResponseDto loginResponse(SimpleUserExample userEntity, String webToken) {
        // 返回前端不显示密码字段
        userEntity.setPassword(null);
        JSONObject respJSON = JSONUtil.parseObj(userEntity);

        respJSON.set("token", webToken);
        return ResultUtil.msg(true, respJSON);
    }



    /**
     * 查询抽取专家的记录
     * @author tian
     * @date 2022-4-14 16:39
     * @param expertGroupMembersDTO
     * @return org.fzzn.core.model.msg.ResponseDto
     */
    @ApiOperation(value = "查询抽取专家的记录", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "groupId", value = "抽取记录id", dataTypeClass = Long.class)
    })
    @PostMapping("/api/expert/selectExpertGroupMembersByGroupId")
    public ResponseDto selectExpertGroupMembersByGroupId(@RequestBody ExpertGroupMembersDTO expertGroupMembersDTO) {
        if (null == expertGroupMembersDTO.getGroupId()) {
            return ResultUtil.fail(MsgEnum.INCORRECT_PARAM);
        }
        return ResultUtil.msg(expertClient.selectExpertGroupMembersByGroupId(expertGroupMembersDTO));
    }



    /**
     * 查询补抽专家
     * @author tian
     * @date 2022-4-14 16:40
     * @param expertGroupMembersDTO
     * @return org.fzzn.core.model.msg.ResponseDto
     */
    @ApiOperation(value = "查询补抽专家", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "id", value = "抽取专家的id", dataTypeClass = Long.class)
    })
    @PostMapping("/api/expert/supplementExtract")
    public ResponseDto supplementExtract(@RequestBody ExpertGroupMembersDTO expertGroupMembersDTO){
        if (CollectionUtils.isEmpty(expertGroupMembersDTO.getSupplementExtractList())) {
            return ResultUtil.fail(MsgEnum.INCORRECT_PARAM);
        }
        expertGroupMembersDTO.setCreateId(ShiroUtil.getUserId());
        expertGroupMembersDTO.setCreateName(ShiroUtil.getUser().getFullName());
        expertGroupMembersDTO.setOrgId(ShiroUtil.getOrgId());
        return ResultUtil.msg(expertClient.supplementExtract(expertGroupMembersDTO));
    }
}
